package com.wanwu.channel.remote.cmbpay;


import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.wanwu.channel.common.enums.ExceptionEnum;
import com.wanwu.channel.common.enums.TradeStatusEnum;
import com.wanwu.channel.common.exception.SystemException;
import com.wanwu.channel.common.util.HttpUtil;
import com.wanwu.channel.common.util.LogUtil;
import com.wanwu.channel.common.util.XmlUtil;
import jodd.http.HttpResponse;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

/**
 * @author runquanchen
 * @version 1.0
 * @date 2020-02-13 18:14
 * @project channel
 */
@Component
public class CMBHttp {
    private static final Logger logger = LoggerFactory.getLogger(CMBHttp.class);
    @Value("${cmb.suppay.http.url}")
    private  String url ;
    private static String charset = "GBK";
    //数据格式
    private static final String DATTYP = "2";
    //期望时间默认值
    public static final String EPTTIM = "000000";
    //收方信息不检查标志
    public static final String CRTFLG = "Y";
    //业务种类
    public static final String TRSTYP = "100001";
    //行内收方账号户名校验
    public static final String RCVCHK = "1";
    //业务模式编号默认值
    public static final String MODALS = "CBS支付";
    //人民币币种代码
    public static final String CCYNBR = "10";
    //用途  写死已和财务产品确认
    public static final String NUSAGE = "支付货款-万里目";

    public static final Map<String,String> cmbRtCodeMap =new HashMap<>();


    @PostConstruct
    public void init() {
        cmbRtCodeMap.put("0","成功");
        cmbRtCodeMap.put("-1","提交主机失败");
        cmbRtCodeMap.put("-2","执行失败");
        cmbRtCodeMap.put("-3","数据格式错误");
        cmbRtCodeMap.put("-4","尚未登录系统");
        cmbRtCodeMap.put("-5","请求太频繁");
        cmbRtCodeMap.put("-6","不是证书卡用户");
        cmbRtCodeMap.put("-7","用户取消操作");
        cmbRtCodeMap.put("-9","其它错误");

        cmbRtCodeMap.put("AUT","等待审批");
        cmbRtCodeMap.put("NTE","终审完毕");
        cmbRtCodeMap.put("WCF","订单待确认(商务支付用)");
        cmbRtCodeMap.put("BNK","银行处理中");
        cmbRtCodeMap.put("FIN","完成");
        cmbRtCodeMap.put("ACK","等待确认(委托贷款用)");
        cmbRtCodeMap.put("APD","待银行确认(国际业务用)");
        cmbRtCodeMap.put("OPR","数据接收中(代发)");

        cmbRtCodeMap.put("S","银行支付成功");
        cmbRtCodeMap.put("F","银行支付失败");
        cmbRtCodeMap.put("B","银行支付被退票");
        cmbRtCodeMap.put("R","企业审批否决");
        cmbRtCodeMap.put("D","企业过期不审批");
        cmbRtCodeMap.put("C","企业撤销");
        cmbRtCodeMap.put("M","商务支付");
        cmbRtCodeMap.put("V","委托贷款被借款方拒绝");


    }


    @Data
    @JacksonXmlRootElement(localName = "CMBSDKPGK")
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class CmbskdpgkReq {
        @JacksonXmlProperty(localName = "INFO")
        private InfoReq info;
        @JacksonXmlProperty(localName = "NTQRYSTYX1")
        private Ntqrystyx1 ntqrystyx1;


    }

    @Data
    public static class InfoReq {
        @JacksonXmlProperty(localName = "FUNNAM")
        private String funnam;//函数名
        @JacksonXmlProperty(localName = "DATTYP")
        private String dattyp = DATTYP;//数据格式
        @JacksonXmlProperty(localName = "LGNNAM")
        private String lgnnam;//登陆用户名
    }

    @Data
    public static class InfoRsp {
        @JacksonXmlProperty(localName = "FUNNAM")
        private String funnam;//函数名
        @JacksonXmlProperty(localName = "DATTYP")
        private String dattyp;//数据格式
        @JacksonXmlProperty(localName = "RETCOD")
        private String retcod;//返回代码
        @JacksonXmlProperty(localName = "ERRMSG")
        private String errmsg;//错误信息
        @JacksonXmlProperty(localName = "LGNNAM")
        private String lgnnam;

        public boolean isSuccess() {
            return "0".equals(retcod);
        }
    }

    @Data
    public static class Ntqrystyx1 {
        @JacksonXmlProperty(localName = "BUSCOD")
        private String buscod;//业务类型
        @JacksonXmlProperty(localName = "YURREF")
        private String yurref;//业务参考号
        @JacksonXmlProperty(localName = "BGNDAT")
        private String bgndat;//起始日期
        @JacksonXmlProperty(localName = "ENDDAT")
        private String enddat;//结束日期

    }

    @Data
    @JacksonXmlRootElement(localName = "CMBSDKPGK")
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class CmbskdpgkResp {
        @JacksonXmlProperty(localName = "INFO")
        private InfoRsp info;
        @JacksonXmlProperty(localName = "NTSTLLSTZ")
        private Ntstllstz ntstllstz;


    }

    @Data
    public static class Ntstllstz {
        @JacksonXmlProperty(localName = "REQNBR")
        private String reqnbr;//流程实例号
        @JacksonXmlProperty(localName = "BUSCOD")
        private String buscod;//业务编码
        @JacksonXmlProperty(localName = "BUSMOD")
        private String busmod;//业务模式
        @JacksonXmlProperty(localName = "DBTBBK")
        private String dbtbbk;//转出分行号
        @JacksonXmlProperty(localName = "DBTACC")
        private String dbtacc;//付方帐号
        @JacksonXmlProperty(localName = "CRTBBK")
        private String crtbbk;//收方分行号
        @JacksonXmlProperty(localName = "CRTACC")
        private String crtacc;//收方帐号
        @JacksonXmlProperty(localName = "CRTNAM")
        private String crtnam;//收方名称
        @JacksonXmlProperty(localName = "CCYNBR")
        private String ccynbr;//币种
        @JacksonXmlProperty(localName = "TRSAMT")
        private String trsamt;//交易金额
        @JacksonXmlProperty(localName = "EPTDAT")
        private String eptdat;//期望日
        @JacksonXmlProperty(localName = "EPTTIM")
        private String epttim;//期望时间
        @JacksonXmlProperty(localName = "OPRDAT")
        private String oprdat;//经办日
        @JacksonXmlProperty(localName = "YURREF")
        private String yurref;//对方参考号
        @JacksonXmlProperty(localName = "REQSTS")
        private String reqsts;//请求状态
        @JacksonXmlProperty(localName = "RTNFLG")
        private String rtnflg;//业务处理结果
        @JacksonXmlProperty(localName = "ATHFLG")
        private String athflg;//是否有附件信息
        @JacksonXmlProperty(localName = "RSV30Z")
        private String resv30z;//保留字 30

        public boolean isFail() {
            return "F".equals(rtnflg) || "B".equals(rtnflg) || "R".equals(rtnflg) || "D".equals(rtnflg) || "M".equals(rtnflg) || "C".equals(rtnflg);

        }

    }


    /**
     * 招商银行银企直连直接支付请求对象
     *
     * @Author Meng weilong
     * @Date 2020/2/14 5:29 下午
     **/
    @Data
    @JacksonXmlRootElement(localName = "CMBSDKPGK")
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class CmbPayReq {
        @JacksonXmlProperty(localName = "INFO")
        private InfoReq info;
        @JacksonXmlProperty(localName = "SDKPAYRQX")
        private Sdkpayrqx sdkpayrqx;
        @JacksonXmlProperty(localName = "DCOPDPAYX")
        private Dcopdpayx dcopdpayx;
    }

    @Data
    public static class Sdkpayrqx {
        /**
         * 业务类别
         * N02031:直接支付 N02041:直接集团支付
         **/
        @JacksonXmlProperty(localName = "BUSCOD")
        private String buscod;
        /**
         * 业务模式编号
         * 默认为 00001
         **/
        @JacksonXmlProperty(localName = "BUSMOD")
        private String busmod;
        /**
         * 业务模式名称
         **/
        @JacksonXmlProperty(localName = "MODALS")
        private String modals;
    }

    @Data
    public static class Dcopdpayx {
        /**
         * 业务参考编号
         **/
        @JacksonXmlProperty(localName = "YURREF")
        private String yurref;
        /**
         * 期望日 默认当前日期
         **/
        @JacksonXmlProperty(localName = "EPTDAT")
        private String eptdat;
        /**
         * 期望时间 默认 000000
         **/
        @JacksonXmlProperty(localName = "EPTTIM")
        private String epttim;
        /**
         * 付方账号
         **/
        @JacksonXmlProperty(localName = "DBTACC")
        private String dbtacc;
        /**
         * 付方开户地区代码
         **/
        @JacksonXmlProperty(localName = "DBTBBK")
        private String dbtbbk;
        /**
         * 交易金额
         **/
        @JacksonXmlProperty(localName = "TRSAMT")
        private String trsamt;
        /**
         * 币种代码 附录A.3
         **/
        @JacksonXmlProperty(localName = "CCYNBR")
        private String ccynbr;
        /**
         * 结算方式代码 N:普通 F:快速
         **/
        @JacksonXmlProperty(localName = "STLCHN")
        private String stlchn;
        /**
         * 用途
         **/
        @JacksonXmlProperty(localName = "NUSAGE")
        private String nusage;
        /**
         * 业务摘要
         **/
        @JacksonXmlProperty(localName = "BUSNAR")
        private String busnar;
        /**
         * 收方账号
         **/
        @JacksonXmlProperty(localName = "CRTACC")
        private String crtacc;
        /**
         * 收方账户名
         **/
        @JacksonXmlProperty(localName = "CRTNAM")
        private String crtnam;
        /**
         * 收方长户名
         **/
        @JacksonXmlProperty(localName = "LRVEAN")
        private String lrvean;
        /**
         * 收方行号
         **/
        @JacksonXmlProperty(localName = "BRDNBR")
        private String brdnbr;
        /**
         * 系统内外标志  Y:招行;N:非招行
         **/
        @JacksonXmlProperty(localName = "BNKFLG")
        private String bnklg;
        /**
         * 收方开户行  跨行支付(BNKFLG=N)必填
         **/
        @JacksonXmlProperty(localName = "CRTBNK")
        private String crtbnk;
        /**
         * 城市代码 CRTFLG不为Y时行内支付必填
         **/
        @JacksonXmlProperty(localName = "CTYCOD")
        private String ctycod;
        /**
         * 收方行地址  跨行支付(BNKFLG=N)必填;CRTFLG不为Y时行内支付必填
         **/
        @JacksonXmlProperty(localName = "CRTADR")
        private String crtadr;
        /**
         * 收方信息不检查标志  Y:行内支付不检查城市代码和收方行地址 默认为Y
         **/
        @JacksonXmlProperty(localName = "CRTFLG")
        private String crtflg;
        /**
         * 收方电子邮件
         **/
        @JacksonXmlProperty(localName = "NTFCH1")
        private String ntfch1;
        /**
         * 收方移动电话
         **/
        @JacksonXmlProperty(localName = "NTFCH2")
        private String ntfch2;
        /**
         * 收方编号
         **/
        @JacksonXmlProperty(localName = "CRTSQN")
        private String crtsqn;
        /**
         * 业务种类  100001=普通汇兑 101001=慈善捐款 101002=其他 默认 100001
         **/
        @JacksonXmlProperty(localName = "TRSTYP")
        private String trstyp;
        /**
         * 行内收方账号户名校验  1:校验 空或者其他值:不校验
         **/
        @JacksonXmlProperty(localName = "RCVCHK")
        private String rcvchk;
        /**
         * 保留字段
         **/
        @JacksonXmlProperty(localName = "RSV28Z")
        private String rsv28z;
    }

    @Data
    public static class Ntqpayrqz {
        /**
         * 流水号
         **/
        @JacksonXmlProperty(localName = "SQRNBR")
        private String sqrnbr;
        /**
         * 业务参考号
         **/
        @JacksonXmlProperty(localName = "YURREF")
        private String yurref;
        /**
         * 流程实例号
         **/
        @JacksonXmlProperty(localName = "REQNBR")
        private String reqnbr;
        /**
         * 业务请求状态
         **/
        @JacksonXmlProperty(localName = "REQSTS")
        private String reqsts;
        /**
         * 业务处理结果
         **/
        @JacksonXmlProperty(localName = "RTNFLG")
        private String rtnflg;
        /**
         * 待处理操作序列
         **/
        @JacksonXmlProperty(localName = "OPRSQN")
        private String oprsqn;
        /**
         * 操作别名
         **/
        @JacksonXmlProperty(localName = "OPRALS")
        private String oprals;
        /**
         * 错误码
         **/
        @JacksonXmlProperty(localName = "ERRCOD")
        private String errcod;
        /**
         * 错误文本
         **/
        @JacksonXmlProperty(localName = "ERRTXT")
        private String errtxt;
    }

    @Data
    @JacksonXmlRootElement(localName = "CMBSDKPGK")
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class CmbPayResp {
        @JacksonXmlProperty(localName = "INFO")
        private InfoRsp info;
        @JacksonXmlProperty(localName = "NTQPAYRQZ")
        private Ntqpayrqz ntqpayrqz;
    }

    public static void main(String[] args) {

        CmbskdpgkReq cm = new CmbskdpgkReq();

        InfoReq info = new InfoReq();
        info.setFunnam("1");
        info.setDattyp("w");

        info.setLgnnam("3");

        Ntqrystyx1 ntqrystyx1 = new Ntqrystyx1();
        ntqrystyx1.setBuscod("4");
        ntqrystyx1.setYurref("t");
        ntqrystyx1.setBgndat("6");
        ntqrystyx1.setEnddat("7");

        cm.setInfo(info);
        cm.setNtqrystyx1(ntqrystyx1);
        CmbskdpgkResp respw = (CmbskdpgkResp) new CMBHttp().request(cm, CmbskdpgkResp.class);
        System.out.println(JSON.toJSONString(respw));


        System.out.println(XmlUtil.toXml(null));

        String req = "<?xml version=\"1.0\" encoding = \"GBK\"?>\n" +
                "<CMBSDKPGK>\n" +
                "    <INFO>\n" +
                "        <DATTYP>2</DATTYP>\n" +
                "        <ERRMSG></ERRMSG>\n" +
                "        <FUNNAM>NTQRYSTY</FUNNAM>\n" +
                "        <LGNNAM>QGZ01</LGNNAM>\n" +
                "        <RETCOD>0</RETCOD>\n" +
                "    </INFO>\n" +
                "    <NTSTLLSTZ>\n" +
                "        <BUSCOD>N02031</BUSCOD>\n" +
                "        <BUSMOD>00001</BUSMOD>\n" +
                "        <CCYNBR>10</CCYNBR>\n" +
                "        <CRTACC>769900016610303</CRTACC>\n" +
                "        <CRTNAM>中天世纪集团</CRTNAM>\n" +
                "        <DBTACC>769900038110701</DBTACC>\n" +
                "        <DBTBBK>69</DBTBBK>\n" +
                "        <EPTDAT>20151027</EPTDAT>\n" +
                "        <EPTTIM>000000</EPTTIM>\n" +
                "        <OPRDAT>20151027</OPRDAT>\n" +
                "        <REQNBR>0000977509</REQNBR>\n" +
                "        <REQSTS>FIN</REQSTS>\n" +
                "        <RTNFLG>S</RTNFLG>\n" +
                "        <TRSAMT>12.10</TRSAMT>\n" +
                "        <YURREF>SA201510271C20E25406554A87B581</YURREF>\n" +
                "    </NTSTLLSTZ>\n" +
                "</CMBSDKPGK>";

        CmbskdpgkResp resp = XmlUtil.toBean(req, CmbskdpgkResp.class);
        System.out.println(resp.getInfo().getDattyp());

    }

    public Object request(Object req, Class respClass) {

        try {
            if (req == null) {
                return null;
            }

            String reqStr = buildXml(req);
            LogUtil.info(logger, "请求招商前置机{0}明文:{1}",url, reqStr);
            HttpResponse response = HttpUtil.postGbk(url, reqStr, null, null);
            if (response == null || response.statusCode() != 200 || StringUtils.isEmpty(response.bodyText()) || response.bodyBytes() == null) {
                LogUtil.error(logger, "请求招商前置机接口异常，返回response:{0}", response);
                throw new SystemException(ExceptionEnum.E10044, TradeStatusEnum.FAIL);
            }
            String respStr = new String(response.bodyBytes(), Charset.forName(charset));
            LogUtil.info(logger, "请求招商前置机接口返回报文:{0}", respStr);

            Object httpDataResp = XmlUtil.toBean(respStr, respClass);

            if (httpDataResp == null) {
                LogUtil.error(logger, "请求招商前置机接口返回报文转换异常");
                throw new SystemException(ExceptionEnum.E10044, TradeStatusEnum.FAIL);
            }
            return httpDataResp;

        }catch (UnsupportedEncodingException ue){
            LogUtil.error(logger, ue, "请求招商前置机接口异常");
            throw new SystemException(ExceptionEnum.E10048, TradeStatusEnum.FAIL);
        } catch (Exception e) {
            if (e instanceof SystemException) {
                throw e;
            } else {
                LogUtil.error(logger, e, "请求招商前置机接口异常");
                throw new SystemException(ExceptionEnum.E10044, TradeStatusEnum.FAIL);
            }
        }
    }

    private static String buildXml(Object req) {
        String headStr = "<?xml version=\"1.0\" encoding = \"GBK\"?>\n";
        String body = XmlUtil.toXml(req);
        return headStr + body;
    }


}
